// 未经审查
// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 此文件实现FindExportData。

package importer

import (
	"bufio"
	"fmt"
	"io"
	"strconv"
	"strings"
)

func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
	// 见$GOROOT/include/ar.h。
	hdr := make([]byte, 16+12+6+6+8+10+2)
	_, err = io.ReadFull(r, hdr)
	if err != nil {
		return
	}
	// 去调试
	if false {
		fmt.Printf("header: %s", hdr)
	}
	s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
	size, err = strconv.Atoi(s)
	if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
		err = fmt.Errorf("invalid archive header")
		return
	}
	name = strings.TrimSpace(string(hdr[:16]))
	return
}

// FindExportData将读取器r定位在
// 导出基础GC创建的对象/存档的数据部分
// 通过从中读取文件。读卡器必须位于
// 在调用此函数之前启动文件。hdr结果
// 是导出数据之前的字符串，可以是“$$”或“$$B”。
// None
func FindExportData(r *bufio.Reader) (hdr string, err error) {
	// 读取第一行以确保这是一个对象文件。
	line, err := r.ReadSlice('\n')
	if err != nil {
		err = fmt.Errorf("can't find export data (%v)", err)
		return
	}

	if string(line) == "!<arch>\n" {
		// 存档文件。扫描到_uu.PKGDEF。
		var name string
		if name, _, err = readGopackHeader(r); err != nil {
			return
		}

		// 第一个条目应该是_u.PKGDEF。
		if name != "__.PKGDEF" {
			err = fmt.Errorf("go archive is missing __.PKGDEF")
			return
		}

		// 读取_u.PKGDEF数据的第一行，使该行
		// 再次是输入的第一行。
		if line, err = r.ReadSlice('\n'); err != nil {
			err = fmt.Errorf("can't find export data (%v)", err)
			return
		}
	}

	// 现在在存档文件中的_uu.PKGDEF，或者仍然在文件的开头。
	// 无论哪种方式，行都应该以“go object”开头。
	if !strings.HasPrefix(string(line), "go object ") {
		err = fmt.Errorf("not a Go object file")
		return
	}

	// 跳过对象标题以导出数据。
	// 在以$$开头的第一行之后开始。
	for line[0] != '$' {
		if line, err = r.ReadSlice('\n'); err != nil {
			err = fmt.Errorf("can't find export data (%v)", err)
			return
		}
	}
	hdr = string(line)

	return
}
